#include "Test.hpp"

const int processnum = 10;
std::vector<task_t> tasks;

struct channel
{
    int _cmdfd;
    pid_t _slaverid;
    std::string _processname;

    channel(int cmdfd, int slaverid, const std::string &processname)
        : _cmdfd(cmdfd), _slaverid(slaverid), _processname(processname)
    {
    }
};

void slaver()
{
    while (true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(cmdcode));
        if (n == sizeof(cmdcode))
        {
            cout << getpid() << " : child say : "
                 << "i get a code : " << cmdcode << endl;
            cout << "do the task :" << endl;
            tasks[cmdcode]();
        }
        if (n == 0)
            break;
    }
}

void InitProcessPool(std::vector<channel> *channels)
{
    for (int i = 0; i < processnum; ++i)
    {
        int pipefd[2];
        int n = pipe(pipefd);
        assert(!n);
        (void)n;

        pid_t id = fork();
        if (id == 0)
        {
            // child
            for (int i = 4; i <= pipefd[1]; ++i)
                close(i);
            dup2(pipefd[0], 0); // 将标准输入重定向到管道读入
            close(pipefd[0]);
            slaver();
            exit(0);
        }
        // parent
        close(pipefd[0]);

        // 添加channel字段
        std::string name = "process-" + std::to_string(i);
        channels->push_back(channel(pipefd[1], id, name));
    }
}

void DeBug(const std::vector<channel> &channels)
{
    for (auto &c : channels)
    {
        std::cout << c._slaverid << ':' << c._processname << "->" << c._cmdfd << std::endl;
    }
}

void QuitProcess(const std::vector<channel> &channels)
{
    for (auto &c : channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid, nullptr, 0);
    }
    sleep(3);
}

void menu()
{
    printf("****************************\n");
    printf("***任务选项: 1、2、3、4、5***\n");
    printf("***退出选项: 0            ***\n");
    printf("****************************\n");
}

int main()
{
    srand((unsigned int)time(nullptr));
    Loadtasks(&tasks);
    std::vector<channel> channels;

    // 1、初始化
    InitProcessPool(&channels);
    DeBug(channels);

    // 2、开始控制子进程
    while (true)
    {
        menu();
        cout << "@Please Enter:";
        int input = 0;
        std::cin >> input;
        if (!input)
            break;

        // 1、选择任务
        int cmdcode = rand() % tasks.size();

        // 2、选择进程
        int processpos = input % processnum;

        // 3、发送任务
        cout << getpid() << " father say : cmdcode-- " << cmdcode << "already send to id: "
             << channels[processpos]._slaverid << channels[processpos]._processname << endl;
        write(channels[processpos]._cmdfd, &cmdcode, sizeof(cmdcode));

        sleep(1);
    };

    // 3、清理资源
    QuitProcess(channels);

    return 0;
}
